侧边栏切换

lwIP ARP协议分析

最后编辑于: 2010-01-06 20:05  |  分类: web技术  |  标签: lwip   |  浏览数: 1096  |  评论数: 0


总的来说,lwip将链路层ethernet的协议分组格式分为ether和etherarp分开处理。

ip分组先进入 etharp\ip\input 更新一下arp表项,然后直接进入netif的input传递给上层ip层。

arp分组直接进入 etharp\arp\input, 不送入ip层。

奇怪的是,lwip把ether header的结构定义在etharp中。

1. ARP 数据结构

// arp表状态  
enum etharp_state {  
  ETHARP_STATE_EMPTY,  /* 表项空 */  
  ETHARP_STATE_PENDING,  
  ETHARP_STATE_STABLE, /* 稳定状态表项,该表项中MAC值可直接取出 */  
  ETHARP_STATE_EXPIRED  /* 超时表项 */  
};

// arp表项结构  
struct etharp_entry {  
  struct pbuf *p;  /* arp 请求队列 */  
  struct ip_addr ipaddr;  
  struct eth_addr ethaddr;  
  enum etharp_state state;  
  u8_t ctime; /* 超时值 */  
};

// ARP 链路层协议分组  
struct etharp_hdr {  
  struct eth_hdr ethhdr; /* ether header */  
  u16_t hwtype;  
  u16_t proto;  
  u16_t _hwlen_protolen;  
  u16_t opcode;  
  struct eth_addr shwaddr;  
  struct ip_addr2 sipaddr;  
  struct eth_addr dhwaddr;  
  struct ip_addr2 dipaddr;  
}

2. ARP 函数

初始化所有静态ARP表项,状态为EMPTY。

首先排除广播、多播及any地址。然后,将ipaddr及ethaddr对加入arp表项中,该表项索引由find_entry获得。加入后,将该arp表项中还未发送的IP包(这些IP包是由etharp_ouput函数,在处理IP包发送时,由于未找到对应ip的mac地址,由etharp_query加入到 pending arp的未发送IP包链表中。现在我们得到mac和ip对应值后,就可以将这些IP包发送出去), 发送到netif驱动。该函数被etharp_ip_input及etharp_arp_input调用。

查询包含ipaddr的表项。

查询优先级:1. pending 2. stable 3. empty。

find_entry总是根据这些优先级查找是否由匹配项,如果有,立刻返回该项索引。否则根据优先级产看是否有过期表项,并覆盖它。

该函数是再ip分组传上ip层之前,将ip分组的mac和ip映射到arp表项中做更新。这样的设计好像比较浪费。完全可以加大arp表项,去除该过程

arp分组到来,直接交给该函数处理。无论netif的ip地址是否被配置过,都将该ARP分组的源ip和mac地址加入到ARP表项中。如果一个ARP请求的目的ip地址是本地ip地址, 则发送response ARP分组。

该函数分开处理两种地址类型的网络层包,

1) 多播及广播。直接调用netif->linkoutput发送出去,该函数为网卡驱动。

2) 单播。单播的IP包又分三种处理方式。

a. 目的ip在arp表项中,并且stable。则直接构造以太头,调用网卡驱动,发送以太帧。

b. 目的ip不在arp表项中,修改arp表项状态为pending,并调用etharp_request,发送ARP REQUEST。

c. 目的ip在ARP表项中。但状态为pending(这个状态是由b条件引起的,可能ARP RESPONSE在处理该条件时还为返回)。将待发送的IP包的缓冲区PBUF_REF替换成PBUF_POOL或PBUF_RAM(暂时不知道为啥)。这些包将会在update_arp_input中被发送。

3. ARP协议处理流程图


上一篇: 将主机字节序转换为网络字节序的htonx函数

下一篇: hc、ac、ls等的区别与意义